package datamining.algorithms.prefixspan;

import java.util.Collection;
import java.util.TreeMap;

import datamining.miner.chain.Extension;
import datamining.miner.chain.GenerationPartialStep;
import datamining.miner.chain.MiningStep;
import datamining.miner.chain.SearchLatticeNode;
import datamining.miner.enviroment.LocalEnvironment;
import datamining.miner.general.Embedding;
import datamining.miner.general.ExtendedEmbedding;
import datamining.miner.general.SequenceFragment;
import datamining.sequence.IndexedItem;
import datamining.sequence.Sequence;

/**
 * <p>
 * 创建于 2012-12-11 下午5:08:11
 * 
 * @author xujinghu (jinghuxu@nudt.edu.cn) <br>
 *         Copyright 2012 xujinghu <br>
 *         Lisence: Apache
 */
public class RightMostExtension<ItemType> extends
		GenerationPartialStep<ItemType> {

	private PThreadEnvironment<ItemType> tenv;
	private LocalEnvironment<ItemType> env;
	private int counter = 0;
	private TreeMap<IndexedItem<ItemType>, PrefixSpanExtension<ItemType>> children;// 子序列扩展项与父序列扩展项的对应关系

	public RightMostExtension(MiningStep<ItemType> next,
			final PThreadEnvironment<ItemType> tenv) {
		super(next);
		this.tenv = tenv;
		this.env = LocalEnvironment.env();
		this.children = new TreeMap<IndexedItem<ItemType>, PrefixSpanExtension<ItemType>>();
	}

	@Override
	public void call(SearchLatticeNode<ItemType> node,
			Collection<Extension<ItemType>> extensions) {
		extensions.clear();
		extensions.addAll(children.values());
		callNext(node, extensions);
	}

	@Override
	public void call(SearchLatticeNode<ItemType> node,
			Embedding<ItemType> embedding) {
		counter++;
		extend((PrefixCode<ItemType>) node,
				(ExtendedEmbedding<ItemType>) embedding);
		callNext(node, embedding);

	}

	protected final void extend(final PrefixCode<ItemType> code,
			final ExtendedEmbedding<ItemType> emb) {
		final PrefixSpanSequence<ItemType> dbs = (PrefixSpanSequence<ItemType>) emb
				.getIndexedSequence();

		IndexedItem<ItemType> subLastItem = code.getLatItem();// 子序列最后一项
		IndexedItem<ItemType> subExtendItem;// 子序列新扩展项
		IndexedItem<ItemType> superLastItem = emb
				.getSuperSequenceItem(subLastItem);// 父序列对应子序列的最后一项
		IndexedItem<ItemType> superExtendItem = superLastItem;// 父序列新扩展项
		boolean isNewSet = false;

		while (superExtendItem.next != null) {
			superExtendItem = superExtendItem.next;// 寻找可能的扩展项
			isNewSet = (superExtendItem.itemSetIndex != superLastItem.itemSetIndex);// 判断是否新项集

			if (isNewSet) {// 新项集
				subExtendItem = new IndexedItem<ItemType>(
						subLastItem.itemSetIndex + 1,
						0, superExtendItem.label);
			} else {// 非新项集
				subExtendItem = new IndexedItem<ItemType>(
						subLastItem.itemSetIndex,
						subLastItem.itemIndex + 1,
						superExtendItem.label);
			}

			PrefixSpanExtension<ItemType> ext = children
					.get(subExtendItem);

			if (env.storeEmbeddings) {
				// TODO:关于embedding的搜索
				if (ext == null) {// 如果是项的第一次出现
					final Sequence<ItemType> new_seq = code
							.toFragment()
							.toSequence().clone();

					new_seq.append(superExtendItem.label,
							isNewSet);// TODO:根据新扩展的项是否在新的项集合中，添加新的项到已有序列
					final SequenceFragment<ItemType> f = tenv
							.getFragment(new_seq);

					ext = tenv.getExtension(subExtendItem,
							 f);// 保存实际扩展（包括实际扩展项和扩展后的序列fragment）
					//ext.code = code.extend(ext);
					children.put(subExtendItem, ext);// 保存逻辑扩展项和实际扩展的对应关系
				} else {
					subExtendItem.release(tenv);
				}
				ext.getFragment().add(emb.extend(ext, superExtendItem));// 将新的embedding存储到扩展中
			} else {
				// TODO
				ext.getFragment().add(dbs);
			}
		}
	}
	
	public void reset() {
		children.clear();
		resetNext();
	}
}
